// ------------------------------------------------------------------------------------------------
// File   : DX9VertexShaderManager.h
// Date   : 2012-08-01
// Author : Weng xiao yi
// Descr. : 
//
// ------------------------------------------------------------------------------------------------

#ifndef OY_DX9VERTEXSHADERMGR_H
#define OY_DX9VERTEXSHADERMGR_H

#include <map>
#include <windows.h>

enum EDX9VSMaterials
{
	eVSMaterial_Default,
	eVSMaterial_AfterEffect,
	eVSMaterial_AdvancedWater,
	eVSMaterial_SpaceBump,
	eVSMaterial_SoftParticle,
	eVSMaterial_DynamicWeather,

	// Below is Assemble Shader, if using HLSL, please add it upper
	eVSMaterial_GPUSkin,
	eVSMaterial_Shadowmap,
};


// Declaration of the basic class attributes
#define DX9VS_DECLARE_CLASS(_class_, _id_)                                  \
	public:                                                                 \
	_class_(void) { Reset(); }												\
	inline ULONG64 GetKey(void)        { return stKey.ulKey; }				\
	inline UCHAR   GetMaterialID(void) { return stKey.ulMaterialID; }		\
	inline void    Reset(void)         { stKey.ulKey = 0; stKey.ulMaterialID = _id_; }

// ------------------------------------------------------------------------------------------------
// FORWARD DECLARATIONS
// ------------------------------------------------------------------------------------------------
class DX9VertexShader;
struct ID3DXConstantTable;

// DX9VertexShaderManager class definition ------------------------

class DX9VertexShaderManager
{
public:

	// Please increment DX9_SHADER_DB_VERSION (DX9ShaderDatabase.cpp) for any feature change (not necessary if adding a new material or variable.)

	class DX9VSFeature
	{
	public:

		virtual inline ULONG64 GetKey(void) = 0;
		virtual inline UCHAR   GetMaterialID(void) = 0;

		const char* BuildFeatureDefinition(char* _szFeatureDefinition);

		virtual void AddSpecificFeatures(CHAR *_szFeatureDefinition) { }

		// Components
		virtual BOOL HasColor0(void)    { return 0; }
		virtual BOOL HasColor1(void)    { return 0; }
		virtual BOOL HasBlendInfo(void) { return 0; }
		virtual BOOL HasNormal(void)    { return 0; }
		virtual BOOL HasTangent(void)   { return 0; }
		virtual BOOL HasTexCoord0(void) { return 0; }
		virtual BOOL HasTexCoord1(void) { return 0; }
		virtual BOOL HasTexCoord2(void) { return 0; }
		virtual BOOL HasTexCoord3(void) { return 0; }
		virtual BOOL HasTexCoord4(void) { return 0; }
		virtual BOOL HasTexCoord5(void) { return 0; }
		virtual BOOL HasTexCoord6(void) { return 0; }
		virtual BOOL HasTexCoord7(void) { return 0; }
		virtual BOOL UseAssemble(void)	{ return 0; }

		virtual const CHAR* GetAssembleShader(void) { return NULL; }

	};

	// Default material
	class DX9VSFeatureDefault : public DX9VSFeature
	{
		DX9VS_DECLARE_CLASS(DX9VSFeatureDefault, eVSMaterial_Default);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		static void PreCache() { }
	};

	// after effects
	class DX9VSFeatureAfterEffect : public DX9VSFeature
	{
		DX9VS_DECLARE_CLASS(DX9VSFeatureAfterEffect, eVSMaterial_AfterEffect);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulEffectId                  : 8;    // After Effect Id
				ULONG64 ulEffectSubType             : 4;    // After Effect sub type
				ULONG64 ulSamplesCount              : 4;    // Number of samples
				ULONG64 ulInputTexCoord0            : 1;
				ULONG64 ulReserved                  : 33;
			};
			ULONG64 ulKey;
		} stKey;

		virtual void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		static void PreCache();
	};



	class DX9VSFeatureAdvancedWater : public DX9VSFeature
	{
		DX9VS_DECLARE_CLASS(DX9VSFeatureAdvancedWater, eVSMaterial_AdvancedWater);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulWaterPassID				: 4;	// Water pass ID for different vertex shader
				ULONG64 ulAssemble					: 1;
				ULONG64 ulReserved                  : 45;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		virtual void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		virtual const CHAR* GetAssembleShader();
		virtual BOOL UseAssemble(void)
		{
			return (stKey.ulAssemble == 1);
		}
		static void PreCache();
	};

	class DX9VSFeatureDynamicWeather : public DX9VSFeature
	{
		DX9VS_DECLARE_CLASS(DX9VSFeatureDynamicWeather, eVSMaterial_DynamicWeather);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		virtual void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		virtual BOOL UseAssemble(void)
		{
			return FALSE;
		}
		static void PreCache();
	};

	class DX9VSFeatureGPUSkin : public DX9VSFeature
	{
		DX9VS_DECLARE_CLASS(DX9VSFeatureGPUSkin, eVSMaterial_GPUSkin);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulGpuSkinID					: 4;	// GPUSkin ID for different vertex shader
				ULONG64 ulAssemble					: 1;
				ULONG64 ulReserved                  : 45;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		//virtual void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		virtual const CHAR* GetAssembleShader();
		virtual BOOL UseAssemble(void)
		{
			return (stKey.ulAssemble == 1);
		}
		static void PreCache();
	};

	class DX9VSFeatureShadowmap : public DX9VSFeature
	{
		DX9VS_DECLARE_CLASS(DX9VSFeatureShadowmap, eVSMaterial_Shadowmap);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulShadowpassID				: 4;	// shadow map pass ID for different vertex shader
				ULONG64 ulAssemble					: 1;
				ULONG64 ulReserved                  : 45;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		virtual const CHAR* GetAssembleShader();
		virtual BOOL UseAssemble(void)
		{
			return (stKey.ulAssemble == 1);
		}
		static void PreCache();
	};

	class DX9VSFeatureSpaceBump : public DX9VSFeature
	{
		DX9VS_DECLARE_CLASS(DX9VSFeatureSpaceBump, eVSMaterial_SpaceBump);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		virtual void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		virtual BOOL UseAssemble(void)
		{
			return FALSE;
		}
		static void PreCache();
	};

	class DX9VSFeatureSoftParticle : public DX9VSFeature
	{
		DX9VS_DECLARE_CLASS(DX9VSFeatureSoftParticle, eVSMaterial_SoftParticle);

		union
		{
			struct
			{
				ULONG64 ulShaderVer					: 6;	// Shader version
				ULONG64 ulMaterialID                : 8;    // Material used for shader setup
				ULONG64 ulReserved                  : 50;   // Used by material to define the features
			};
			ULONG64 ulKey;
		} stKey;

		virtual void AddSpecificFeatures(CHAR* _szFeatureDefinition);
		virtual BOOL UseAssemble(void)
		{
			return FALSE;
		}
		static void PreCache();
	};


	DX9VertexShaderManager();
	~DX9VertexShaderManager();

	inline static DX9VertexShaderManager* GetInstance(void) 
	{ 
		// The one and only instance
		static DX9VertexShaderManager sm_Instance;
		return &sm_Instance;
	}

	void Shutdown(void);

	void InitShadersTable(void);
	void UnloadAll(void);
	void UnloadAllShaders(void);

	void BuildShaderDefinition(DX9VSFeature* _poFeatures, char *_szShaderDefinition);
	DX9VertexShader* GetShader(DX9VSFeature* _poFeatures);

	BOOL GenerateShader(DX9VSFeature* _poFeatures);
	void AddShader(const ULONG64& _ulKey, DX9VertexShader* _pShader);
	void AddCreateShader(const ULONG64& _ulKey, const void* _pCode, ID3DXConstantTable* _pConstantTable);
	void PreLoadShader(const ULONG64& _ulKey, void* _pCode);
	DX9VertexShader* CreateShader(const ULONG64& _ulKey, const void* _pCode, ID3DXConstantTable* _pConstantTable, CHAR* _szName);   

	inline void ResetDefinitionBuffers() { m_szFeatures[0] /*= m_szVertexModifier[0]*/ = NULL; }
	inline CHAR *GetFeatureDefinitionBuffer()          { return m_szFeatures; }

	// data types
	typedef std::map<INT64, DX9VertexShader*> MapVertexShader; 

private: // members

	MapVertexShader                 m_mapLoadedShaders;

	// definition buffers
	CHAR m_szFeatures[4096];
};

#define DX9GetVertexShaderManager() DX9VertexShaderManager::GetInstance()

#endif //OY_DX9VERTEXSHADERMGR_H
